package com.aaron.factory;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 获取单例对象的工厂类,通过反射实例化对象。
 *  使用很简单：UnprocessedRequests s1 = SingletonFactory.getInstance(UnprocessedRequests.class);
 */
public final class SingletonFactory {
    // 对象集合，key是：类的字符串表示 ，value是：创建的对象
    private static final Map<String, Object> OBJECT_MAP = new ConcurrentHashMap<>();

    private SingletonFactory() {
    }

    // 创建某个对象实例，传入的参数是：类
    public static <T> T getInstance(Class<T> c) {
        if (c == null) {
            throw new IllegalArgumentException();
        }
        String key = c.toString();
        if (OBJECT_MAP.containsKey(key)) {
            return c.cast(OBJECT_MAP.get(key));
        } else {
            // computeIfAbsent()方法对hashMap中指定key的值进行重新计算,如果不存在这个key,则添加到hasMap中,value就是k->的值
            return c.cast(OBJECT_MAP.computeIfAbsent(key, k -> {
                try {
                    // 通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器（Constructor）对象
                    // 并调用其newInstance()方法创建对象，适用于无参和有参构造方法。这里是无参方法构造实例化对象
                    return c.getDeclaredConstructor().newInstance();
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    throw new RuntimeException(e.getMessage(), e);
                }
            }));
        }
    }
}
